package org.stwy.lease.contract;

import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.apache.commons.lang.time.DateUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.stwy.comm.base.BaseRecordsServiceImpl;
import org.stwy.lease.quit.QuitEntity;
import org.stwy.lease.quit.QuitService;
import org.stwy.lease.rent.RentEntity;
import org.stwy.lease.rent.RentService;
import org.stwy.pro.asset.AssetEntity;
import org.stwy.pro.asset.AssetService;
import org.stwy.pro.asset.RecordEntity;

import com.rap.common.exception.ServiceException;
import com.rap.common.persistence.IBaseDAO;
import com.rap.common.utils.DateUtil;

/**
 * 合同 服务类
 */
/**
*版权信息 (c) RAP 保留所有权利.
*@author Rap.Codegen
*@Team RAP Team
*@Date 2015-4-17 20:48:15
*<p></p>
*
*@参与人：Rap.Codegen
*/
 
@Service
@Transactional(rollbackFor=Exception.class)
public class ContractService extends BaseRecordsServiceImpl<ContractEntity, String> {

	private static final String SERIAL_NUMBER = "XXXX"; // 流水号格式
	@Autowired
	private ContractDAO dao;
	
	@Autowired
	private AssetService assetService;
	
	@Autowired
	private RentService rentService;
	
	@Autowired
	private ContractAssetService contractAssetService;
	
	@Autowired
	QuitService quitService;
	
	
	@PersistenceContext
	EntityManager em;
	@Override
	protected IBaseDAO getDAO() {
		return dao;
	}
	/**
	 * 新签租赁合同
	 * @param entity
	 * @param assetIds
	 * @return
	 * @throws ServiceException
	 */
	public ContractEntity add(ContractEntity entity, String[] assetIds) throws ServiceException {
		checkContractDate(entity.getBeginDate(), entity.getEndDate());
		if(entity.getHasInitPay()){
			checkInitPayEndDate(entity.getBeginDate(),entity.getInitPayEndDate());
		}
		//保存合同
		entity.setContractState(ContractEntity.CONTRACT_STATE_VALID);
		entity.setContractChangeType(ContractEntity.CONTRACT_CHANGE_TYPE_ADD);
		entity.setReason("出租");
		entity = super.save(entity);
		//保存合同资产
		saveContractAsset(entity,assetIds);
		//变更资产状态
		RecordEntity record = new RecordEntity();
		record.setRecordDate(entity.getBeginDate());
		record.setReason("出租");
		record.setStateAfter(AssetEntity.ASSET_STATUS_RENT);
		assetService.addAssetRecord(record, assetIds);
		
		//如果签合同时已经支付了一次，则添加一条收租记录
		if(entity.getHasInitPay()){
			addInitPayRent(entity);
		}else{
			//生成下次待收租记录
			rentService.addNextToPayRecord(entity,entity.getBeginDate());
		}
		return entity;
	}
	private void saveContractAsset(ContractEntity entity, String[] assetIds) throws ServiceException{
		//删除已有记录
		List<ContractAssetEntity> contractAssets = contractAssetService.findByContractId(entity.getUuid());
		contractAssetService.delete(contractAssets);
		
		//添加
		List<ContractAssetEntity> list = new ArrayList<ContractAssetEntity>();
		for(String assetId : assetIds){
			AssetEntity asset = assetService.get(assetId);
			ContractAssetEntity contractAssetEntity = new ContractAssetEntity();
			contractAssetEntity.setAsset(asset);
			contractAssetEntity.setContract(entity);
			list.add(contractAssetEntity);
		}
		contractAssetService.save(list);
	}
	/**
	 * 初始租金缴纳至期必须大于合同生效日期而且是某月的最后一天
	 * @param contractBeginDate
	 * @param initPayEndDate
	 * @throws ServiceException
	 */
	private void checkInitPayEndDate(Date contractBeginDate,Date initPayEndDate) throws ServiceException{
		if(contractBeginDate.after(initPayEndDate)){
			throw new ServiceException("初始租金缴至期必须大于合同生效日期");
		}
		/*if(DateUtil.getLastDayOfMonth(initPayEndDate).compareTo(initPayEndDate)!=0){
			throw new ServiceException("初始租金缴至期必须为某月的最后一天");
		}*/
	}

	/**
	 * 根据合同信息添加初始收租记录
	 * @param contract
	 * @throws ServiceException
	 */
	private void  addInitPayRent(ContractEntity contract) throws ServiceException{
		RentEntity rent = new RentEntity();
		rent.setContract(contract);
		rent.setBeginDate(contract.getBeginDate());
		rent.setEndDate(contract.getInitPayEndDate());
		rent.setHasPay(1);
		rent.setIsInit(true);
		rent.setMoney(contract.getInitPay());
		rent.setPayDate(contract.getSignDate());
		rent.setShouldPayDate(contract.getSignDate());
		rent.setShouldPayMoney(contract.getInitPay());
		rent.setStatus(1);
		rentService.save(rent);
	}
	/**
	 * 修改信息时，变更类型设置为“修改”
	 */
	public ContractEntity updateContract(ContractEntity entity,
			String[] assetIds) throws ServiceException {
		entity.setContractChangeType(ContractEntity.CONTRACT_CHANGE_TYPE_EDIT);
		entity = super.update(entity);
		
		//保存合同资产
		saveContractAsset(entity,assetIds);
		
		//修改后收租记录信息跟着改变
		changeNextPayRent(entity);
		return entity;
	}
	private void changeNextPayRent(ContractEntity entity) throws ServiceException {
		//删除最后一条待收租记录
		RentEntity lastToPay = rentService.getlastToPayRecordByContractId(entity.getUuid());
		if(lastToPay!=null){
			rentService.delete(lastToPay);
		}
		//判断是否需要增加一条待收租记录，如果需要则按照最新的合同信息增加。
		RentEntity lastHasPay = rentService.getlastHasPayRecordByContractId(entity.getUuid());
		if(lastHasPay!=null){
			if(rentService.shouldAddNextRent(lastHasPay)){
				Date beginDate = DateUtils.addDays(lastHasPay.getEndDate(), 1);
				rentService.addNextToPayRecord(entity,beginDate);
			}
		}else{
			rentService.addNextToPayRecord(entity,entity.getBeginDate());
		}
		
	}

	@Override
	protected Long getLastCode() throws ServiceException {
		return dao.getLastCode();
	}

	@Override
	protected String[] getRecordAttrs() throws ServiceException {
		return new String[]{ALL_ATTR};
	}
	/**
	 * 将资产置为空置状态
	 * @param contractIds
	 * @param endDate
	 * @param reason
	 * @throws ServiceException
	 */
	private void changeAssetToNull(String[] contractIds, Date endDate,
			String reason) throws ServiceException {
		List<ContractAssetEntity> list = contractAssetService.findByContractIds(contractIds);
		String[] assetIds = new String[list.size()];
		int i=0;
		for(ContractAssetEntity contractAsset : list){
			AssetEntity asset = contractAsset.getAsset();
			assetIds[i++]=asset.getUuid();
		}
		RecordEntity record = new RecordEntity();
		record.setRecordDate(endDate);
		record.setReason(reason);
		record.setStateAfter(AssetEntity.ASSET_STATUS_NULL);
		assetService.addAssetRecord(record,assetIds);
	}

	private void addQuitRecord(String[] contractIds, Date endDate, String reason, Double history, Double deposit)
			throws ServiceException {
		for(String contractId:contractIds){
			ContractEntity contract = get(contractId);
			QuitEntity quit = new QuitEntity();
			quit.setContract(contract);
			quit.setQuitDate(endDate);
			quit.setRemark(reason);
			quit.setHistory(history);
			quit.setDeposit(deposit);
			quitService.save(quit);
		}
	}
	/**
	 * 结束合同
	 * @param contractIds
	 * @param endDate
	 * @param contractChangeType
	 * @throws ServiceException
	 */
	private void endContract(String[] contractIds, Date endDate,String reason,String contractChangeType)
			throws ServiceException {
		//变更状态
		RecordEntity record = new RecordEntity();
		record.setRecordDate(endDate);
		record.setReason(reason);
		record.setStateAfter(ContractEntity.CONTRACT_STATE_INVALID);
		addConstractRecord(record, contractIds);
	}
	public boolean addConstractRecord(RecordEntity record, String[] pks) 
			throws ServiceException {
		for(String pk : pks){
			record.setId(pk);
			addConstractRecord(record);
		}
		return true;
		/*List<ContractEntity> list = (List<ContractEntity>) super.findAll(contractIds);
		for(ContractEntity contract : list){
			contract.setContractChangeType(contractChangeType);
			contract.setContractState(ContractEntity.CONTRACT_STATE_INVALID);
			contract.setEndDate(endDate);
			contract.setReason(reason);
		}*/
		
	}

	public boolean addConstractRecord(RecordEntity record) throws ServiceException  {
		try{
			ContractEntity contract = get(record.getId());
			//检查变更时间是否合法
			checkRecordDate(contract.getBeginDate(),contract.getEndDate(),record.getRecordDate());
			//检查状态变更是否合法
			checkChange(contract.getContractState(),record.getStateAfter());
			ContractEntity newEntity = new ContractEntity();
			BeanUtils.copyProperties(contract, newEntity);
			
			//更新资产状态
			newEntity.setContractState(record.getStateAfter());
			newEntity.setEndDate(record.getRecordDate());
			newEntity.setReason(record.getReason());
			update(newEntity);
		}catch(ServiceException e){
			 throw e;
		}catch(Exception e){
			throw new ServiceException("系统异常，未完成变更");
		}
		return true;
	}

	private void checkChange(String contractState, String stateAfter) throws ServiceException {
		if(contractState.equals(stateAfter)){
			throw new ServiceException("合同状态没有变化，不能变更");
		}
	}
	
	private void checkRecordDate(Date beginDate,Date endDate, Date recordDate) throws ServiceException {
		if(recordDate.before(beginDate)){
			throw new ServiceException("变更时间不能小于合同生效时间");
		}
		if(recordDate.after(endDate)){
			throw new ServiceException("变更时间不能大于合同终止时间");
		}
	}

	/**
	 * 退租
	 * 改变合同状态为无效,改变合同结束时间
	 * 添加到退租列表
	 * 改变资产状态为空置
	 * @param deposit 
	 * @param history 
	 * @param record
	 * @return
	 * @throws ServiceException
	 */
	public boolean doQuit(String[] contractIds,Date endDate,String reason, Double history, Double deposit)  throws ServiceException{
		try{
			//1.结束合同
			endContract(contractIds,endDate, reason,ContractEntity.CONTRACT_CHANGE_TYPE_QUIT);
			//2.添加退租记录
			addQuitRecord(contractIds,endDate,reason,history,deposit);
			reason = "退租，退租原因："+reason;
			//3.改变资产状态
			changeAssetToNull(contractIds,endDate,reason);
			//4.删除待收租记录
			removeRents(contractIds);
		}catch(ServiceException e){
			throw e;
		}catch(Exception e){
			throw new ServiceException("系统异常，未完成退租");
		}
		return true;
	}
	
	/**
	 * 根据合同Id删除多余的待缴记录
	 * 逻辑：如果合同的结束日期在待缴记录的开始日期前则该待缴记录是多余的，必须删除
	 * @param contractIds
	 * @throws ServiceException
	 */
	public void removeRents(String[] contractIds) throws ServiceException{
		for(String contractId:contractIds){
			removeRent(contractId);
		}
	}
	public void removeRent(String contractId) throws ServiceException{
		ContractEntity contract = get(contractId);
		//获取最后一条记录
		RentEntity rent = rentService.getlastRecordByContractId(contractId);
		//只处理待缴记录
		if(rent.getHasPay().intValue()==0){
			if(!rent.getBeginDate().before(contract.getEndDate())){
				rentService.delete(rent);
			}
		}
	}
	
	/**
	 * 解除租赁合同
	 * 改变合同状态为无效，改变合同结束时间
	 * 改变资产状态为空置
	 * @param record
	 * @return
	 * @throws ServiceException
	 */
	public boolean doCancel(String[] contractIds,Date endDate,String reason)  throws ServiceException{
		try{
			//1.结束合同
			endContract(contractIds,endDate, reason,ContractEntity.CONTRACT_CHANGE_TYPE_CANCEL);
			//2.改变资产状态
			reason = "解除租赁合同，解除原因："+reason;
			changeAssetToNull(contractIds,endDate,reason);
			//3.删除待收租记录
			removeRents(contractIds);
		}catch(ServiceException e){
			throw e;
		}catch(Exception e){
			throw new ServiceException("系统异常，未完成解除租赁合同");
		}
		return true;
	}
	/**
	 * 续签租赁合同
	 * 改变合同结束时间
	 * @param record
	 * @return
	 * @throws ServiceException
	 */
	public boolean doRenew(ContractEntity renewContract)  throws ServiceException{
		try{
			ContractEntity contract = get(renewContract.getUuid());
			//1检查续签时间 续签日期必须大于上次合同的结束日期
			checkRenewEndDate(contract.getEndDate(),renewContract.getEndDate());
			//2保存续签信息
			renewContract.setStatus(1);
			renewContract.setContractState(ContractEntity.CONTRACT_STATE_VALID);
			renewContract.setContractChangeType(ContractEntity.CONTRACT_CHANGE_TYPE_RENEW);
			super.update(renewContract);
			//3根据需要添加交租记录
			updateRentRecord(renewContract);
		}catch(ServiceException e){
			throw e;
		}catch(Exception e){
			throw new ServiceException("系统异常，未完成续签租赁合同");
		}
		return true;
	}
	// 根据合同找到最后一条收租记录，如果该记录尚未收缴（haspay=false）则啥都不用做，如果该记录已经完成收款，则需要插入一条待缴记录。
	private void updateRentRecord(ContractEntity renewContract)  throws ServiceException{
		RentEntity lastRent = rentService.getlastRecordByContractId(renewContract.getUuid());
		if(lastRent.getHasPay().intValue()==1){
			if(rentService.shouldAddNextRent(lastRent)){
				Date beginDate = DateUtils.addDays(lastRent.getEndDate(), 1);
				rentService.addNextToPayRecord(lastRent.getContract(),beginDate);
			}
		}
	}

	private void checkRenewEndDate(Date oldContractEndDate, Date endDate2)throws ServiceException {
		if(endDate2.compareTo(DateUtils.addDays(oldContractEndDate, 1))<0){
			throw new ServiceException("续签日期必须大于上次合同的结束日期");
		}
	}

	private void checkContractDate(Date beginDate, Date endDate)  throws ServiceException{
		if(beginDate.after(endDate)){
			throw new ServiceException("合同失效日期小于生效日期，请检查是否填写有误");
		}
	}
	/**
	 * 根据合同编号和查询日期获取合同历史记录
	 * @param contractNum
	 * @param date
	 * @return
	 * @throws ServiceException
	 */
	public ContractEntity findByNumAndDate(String contractNum,Date date) throws ServiceException{
		List<ContractEntity> list =dao.findByNumAndDate(contractNum,date);
		if(list==null||list.size()==0){
			return null;
		}
		return list.get(0);
	}
	/**
	 * 查找所有到期结束但是未结束的记录
	 * @param endDate
	 * @return
	 */
	public List<ContractEntity> findNotEndContractsByEndDate(Date endDate) throws ServiceException{
		return dao.findNotEndContractsByEndDate(endDate);
	}
	public String genContractCode()  throws ServiceException{
		String yearMonth = DateUtil.getCurrentDate("yyyyMM");
		String[] codes = dao.findLastContractNumByYearMonth(yearMonth);
		String lastCode;
		if(codes==null||codes.length==0){
			lastCode = null;
		}else{
			lastCode = codes[0];
		}
		return generaterNextNumber(lastCode);
	}
	 public synchronized String generaterNextNumber(String sno) {
	        String id = null;
	        Date date = new Date();
	        SimpleDateFormat formatter = new SimpleDateFormat("yyyyMM");
	        if (sno == null) {
	            id = formatter.format(date) + "0001";
	        } else {
	            int count = SERIAL_NUMBER.length();
	            StringBuilder sb = new StringBuilder();
	            for (int i = 0; i < count; i++) {
	                sb.append("0");
	            }
	            DecimalFormat df = new DecimalFormat("0000");
	            id = formatter.format(date)
	                    + df.format(1 + Integer.parseInt(sno.substring(6, 10)));
	        }
	        return id;
	    }
}
